package main.firefox;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.*;

import org.dbrd.preprocessor.xml.MozillaXMLReportPreprocessor;
import org.sun.dbrd.IdsPreprocessor.VersionOrderMap;
import org.sun.dbrd.mains.AbstractPreprocessorMain;

public class StartDrifting extends AbstractPreprocessorMain {

	public static String projectName = "OpenOffice";
	public static String esIndexName = "openoffice5";

	public static int iteration = 100;
	public static int progress = 0;

	public static int year = 0;

	// 需要在代码中设置好缺陷报告的位置
//	public static String directory = "../../Studied_ITS_Data/" + projectName + "_XMLs/" + "bugs";
	public static String directory = "E:\\replication_package_realistic_vs_classical\\Replication_Package_TSE\\Studied_ITS_Data\\" + projectName + "_XMLs\\" + "bugs";
	public static boolean BM25Fext = false;
	public static String saveDirectory = "./ExtendBackward";
	public static long startingId;
	public long trainingTarget = 0;

	public int threadNum = 10;
	// public static String ResultsDic =
	// "./../../../../scratch1/samy/Eclipse/ExtendBackward2008_40";

	// 需要在代码中设置好结果的目录
	public static String ResultsDic = "./ExtendBackward" + "/"
			+ projectName + "/RandomRealistic100_200";

	// 这个RandomPreviousResearch100Simple文件夹是100chunks_Classical生成的，存着只包含topN的推荐列表
	public static String ResultsDicOld = "../my_100chunks_Classical_with_semantic/ExtendBackward" + "/"
			+ projectName + "/RandomPreviousResearch100Simple";

	public static Map<String, String> startHashMap = new HashMap<String, String>();

	public static boolean fixedWindow = true;

	public static TreeMap<Integer, SortObj> sortingMap;


	public static long topN = 1000;

	public static TreeMap<String, Integer> trainingSizeMap = new TreeMap<String, Integer>();

	public int currentYear;

	public int currentMonth;

	public StartDrifting() {

	}

	public StartDrifting(int month, int year, long trainingTarget) {
		this.currentMonth = month;
		this.currentYear = year;
		this.trainingTarget = trainingTarget;

	}

	public static void main(String[] args) {

		new StartDrifting().mainDo();
	}

	public void mainDo() {
		// TODO Auto-generated method stub

		// Drifting
		// Eclipse from 82056 to 300000 (From 2005 to 2011)
		// Mozilla from 327493 to 587329 (From 2006 t o 2011)
		int tempYear;
		int tempMonth;
		if (projectName.equals("Mozilla")) {
			year = 2010;
		} else if (projectName.equals("Eclipse")) {

			year = 2008;
		} else if (projectName.equals("OpenOffice")) {
			year = 2008;
		}
		int[] yearsOfStudy = { year };
		int trainingSizeTemp = 0;

		System.err.println(projectName + "  " + year
				+ "  --> Started reading CSV. 80 file of years: Just Random  ");

		System.err.println("Started reading CSV file of years");
		// 文件里存储着每一年，每个月的报告id划分
		DataRange_Reader dataRange_Reader = new DataRange_Reader("../../Studied_ITS_Data/" + projectName + "_issues_extra_info/"
				+ projectName + "Drift.csv");

		// 文件里存储着按时间（bug_id大小）顺序排序的报告信息（主要是bug_id，和时间信息）
		SortReaderObj Sort_Reader = new SortReaderObj("../../Studied_ITS_Data/" + projectName + "_issues_extra_info/" + projectName
				+ "Time.csv");
		sortingMap = Sort_Reader.getMapResults();

		int minId = sortingMap.firstKey();
		int maxId = sortingMap.lastKey();

		// This file is generated from the parser of the classical evaluation runs output. It is used to get the exact starts 
		// of the runs, so the realistic work on exact on the same chunks periods. 
		// Can be improved.
		try {
			System.out.println(System.getProperty("user.dir"));
			ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
					"../my_100chunks_Classical_with_semantic/ExtendBackward/" + projectName + "/"
							+ projectName + "_" + 5 + "randomLimit500.DATA"));
			startHashMap = (Map) ois.readObject();
		} catch (Throwable rt) {
			rt.printStackTrace();
			System.out.println();
			System.exit(0);
		}

		System.out.println("First ID== " + minId + " , LastId== " + maxId);

		TreeMap<Integer, TreeMap<Integer, DataRange>> rangesTree = dataRange_Reader
				.getMapResults();
		trainingSizeMap.clear();

		int duplicatesIdWindow = 0;

		ExecutorService prepareThreadsPool = Executors
				.newFixedThreadPool(threadNum);

		System.err
				.println("INDEX: 200 training just Random    ~ Working on year : "
						+ currentYear);

		Random rand = new Random();

		int i = 0;

		trainingSizeTemp = 0;
		int randMaxID = 0;

		File folder = new File(ResultsDicOld);
		File[] listOfFiles = folder.listFiles();
		System.out.println("Size of " + listOfFiles.length);
		// for (i = listOfFiles.length/2; i < listOfFiles.length; i = i + 1) {
		for (i = 0; i < listOfFiles.length; i = i + 1) {
			int randMinId = -1;
			File currentFile = listOfFiles[i];
			String nameStr = currentFile.getName();
			String[] splits = nameStr.split("_");

			randMaxID = Integer.parseInt(splits[2]);

			randMinId = sortingMap.firstKey();

			System.out.println(i + " ->Starting Drifting");
			tempYear = currentYear;
			tempMonth = currentMonth;

			trainingTarget = Integer.parseInt(splits[0]);

			// Actual Start
			int startOffset = Integer.parseInt(splits[1]);
			// Before
			String startAfterTrain = startHashMap.get(splits[2]);

			System.err
					.println(i
							+ " ->Random  Realistic Previous Work Working on  startID: "
							+ randMinId + " , endID:" + randMaxID
							+ " startTrainingID: " + startOffset
							+ " , end TrainingID:" + startAfterTrain);

			// 函数声明
//			public DataPrepareThread(int startOffset, int month, int year,
//			long trainingTarget, int StartId, int endId, int startTrainID,
//			int endTrainID) {
			DataPrepareThread dataPrepareThread = new DataPrepareThread(
					startOffset, currentMonth, currentYear, trainingTarget,
					randMinId, randMaxID, startOffset,
					Integer.parseInt(startAfterTrain));
			prepareThreadsPool.execute(dataPrepareThread);
			System.err
					.println(i
							+ " ->Random  Realistic Previous Work Working on  startID: "
							+ randMinId + " , endID:" + randMaxID);
		}

		prepareThreadsPool.shutdown();
		while (!prepareThreadsPool.isTerminated()) {
			try {
				Thread.sleep(9000L);
			} catch (Throwable throwable) {

			}
		}
		System.err.println("Finished all prepare Threads");

		System.err.println("Finished all threads");

	}

	public static DataRange getPreviousMonthRange(Integer year, Integer Month,
			TreeMap<Integer, TreeMap<Integer, DataRange>> rangesTree) {

		if (Month == 1) {
			Month = 12;
			year--;

		} else {
			Month--;
		}

		return rangesTree.get(year).get(Month);
	}

	@Override
	protected File getMappingFile() {
		return new File(saveDirectory + "/id-" + trainingTarget + "_"
				+ currentMonth + "_" + currentYear + "_"
				+ "-reports.txt-mapping.txt");
	}

	@Override
	protected File getResultFile() {
		return new File(saveDirectory + "/id-" + trainingTarget + "_"
				+ currentMonth + "_" + currentYear + "_" + "-reports-large.txt");
	}

	@Override
	protected File getSummaryFile() {
		return new File(saveDirectory + "/" + trainingTarget + "_"
				+ currentMonth + "_" + currentYear + "_" + "-reports.txt");
	}

	@Override
	protected VersionOrderMap createVersionOrderMap(File versionOrderFile) {
		return new VersionOrderMap(versionOrderFile) {
			@Override
			public int getVersionOrder(String version, int reportId) {
				return 1;
			}

			@Override
			protected void initialize(File versionOrderFile) {
			}
		};
	}

	@Override
	protected File getVersionOrderFile() {
		return null;
	}

	public int getIDBeforeOneYear(int ID) {

		int tempID = ID;
		boolean gotOneYear = true;

		SortObj randomSortObj = sortingMap.get(ID);

		while (gotOneYear && randomSortObj != null) {
			tempID--;
			SortObj sortOb = sortingMap.get(tempID);

			// System.out.println(tempID);
			if (sortOb != null) {

				long startTime = randomSortObj.getDate().getTime();
				long endTime = sortOb.getDate().getTime();
				long diffTime = startTime - endTime;
				long diffDays = diffTime / (1000 * 60 * 60 * 24);
				if (diffDays > 365) {
					gotOneYear = false;
				}
			} else {
				System.err.println("SortObj not found for " + tempID);
			}

			if (sortingMap.firstEntry().equals(tempID) && gotOneYear) {
				tempID = -1;
				gotOneYear = false;

			}

		}

		return tempID;

	}

}

/*
 * class CommandThread extends Thread { private String currentCommand;
 * 
 * public CommandThread(String command) { currentCommand = command; }
 * 
 * @Override public void run() { // TODO Auto-generated method stub
 * executeCommand(currentCommand); }
 * 
 * public String executeCommand(String command) {
 * 
 * StringBuffer output = new StringBuffer();
 * 
 * Process p; try { p = Runtime.getRuntime().exec(command); p.waitFor(); //
 * BufferedReader dd=new BufferedReader(new //
 * InputStreamReader(p.getInputStream())); BufferedReader reader = new
 * BufferedReader(new InputStreamReader( p.getInputStream()));
 * 
 * // InputStreamReader streamReader= new //
 * InputStreamReader(p.getInputStream()); String line = ""; while ((line =
 * reader.readLine()) != null) { System.out.println(line + "\n"); }
 * 
 * System.err.println("Done with Command : " + command);
 * 
 * } catch (Exception e) { e.printStackTrace(); }
 * 
 * return output.toString();
 * 
 * }
 * 
 * }
 */

class DataPrepareThread extends Thread {
	private DataRange tempDataRange;

	private long trainingTarget;

	public int startID;
	public int endId;
	public int startOffset;

	public int startTrainID;
	public int endTrainID;

	public DataPrepareThread(int startOffset, int month, int year,
			long trainingTarget, int StartId, int endId, int startTrainID,
			int endTrainID) {
		this.tempDataRange = new DataRange();
		this.startOffset = startOffset;
		// tempDataRange.setMaxLimit(range.getMaxLimit());
		// tempDataRange.setMinLimit(range.getMinLimit());
		// tempDataRange.setMonth(range.getMonth());
		// tempDataRange.setYear(range.getYear());
		// tempDataRange.setNumberOfReports(range.getNumberOfReports());

		// this.currentMonth = month;
		// this.currentYear = year;
		this.trainingTarget = trainingTarget;
		this.startID = StartId;
		this.endId = endId;

		this.startTrainID = startTrainID;
		this.endTrainID = endTrainID;

	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		executeCommand();
	}

	public void executeCommand() {

		System.err
				.println("Realistic Random gen direction Inside dataprepare thread for : "
						+ " "
						+ trainingTarget
						+ "_"
						+ startID
						+ "_"
						+ endId
						+ "  reports "
						+ " TempYear="
						+ tempDataRange.getYear()
						+ " , TeamMonth="
						+ tempDataRange.getMonth()
						+ " Test period StartID= "
						+ startTrainID				// 就是 startOffset，也就是0_21490_25900_200_21490_25900中的21490
						+ ", EndId="
						+ endTrainID);				// 也就是 0_21490_25900_200_21490_25900中的25900

		int trainingSizeTemp = 200;

		System.err.println("-- Training StartID= " + startTrainID + ", EndId="
				+ endTrainID);
		File filePath = new File(StartDrifting.ResultsDic + "/"
				+ trainingTarget + "_" + startID + "_" + endId + "_"
				+ trainingSizeTemp + "_" + startID + "_" + endId + "_"
				+ "Results");

		File simpleFile = new File(StartDrifting.ResultsDic + "Simple/"
				+ filePath.getName());

		if (simpleFile.exists()) {
			System.err.println("Already exists :  " + simpleFile.getName());
			StartDrifting.progress++;
			System.err.println("Total Done is " + StartDrifting.progress
					+ " , Percentage: % " + ((double) StartDrifting.progress)
					/ ((double) StartDrifting.iteration));

			return;
		}

		
		
		trainingSizeTemp = new MozillaXMLReportPreprocessor(new File(
				StartDrifting.saveDirectory, trainingTarget + "_" + startID
						+ "_" + endId + "_" + "-reports.txt"), new File(
				StartDrifting.directory), (startID), endId).process(
				startOffset, startOffset, StartDrifting.fixedWindow,
				startTrainID, endTrainID);

		System.err.println(" Random gen direction done  processing data.... "
				+ " " + trainingTarget + "_" + startID + "_" + endId
				+ "  reports " + " TempYear=" + tempDataRange.getYear()
				+ " , TeamMonth=" + tempDataRange.getMonth());

		File f = new File(StartDrifting.ResultsDic + "/" + trainingTarget + "_"
				+ startID + "_" + endId + "_" + trainingSizeTemp + "_"
				+ startID + "_" + endId + "_" + "Results");
		if (f.exists()) {
			System.err.println("Already exists :  " + StartDrifting.ResultsDic
					+ "/" + trainingTarget + "_" + startID + "_" + endId + "_"
					+ trainingSizeTemp + "_" + startID + "_" + endId + "_"
					+ "Results");
			return;
		}

		// Add the training Size to the map
		StartDrifting.trainingSizeMap.put(trainingTarget + "_" + startID + "_"
				+ endId, trainingSizeTemp);

		System.err.println("Using training Duplicates : " + trainingSizeTemp
				+ " for " + trainingTarget + "_" + startID + "_" + endId
				+ "  reports ");

		System.out.println("Processing Ids...");

		new StartDrifting(startID, endId, trainingTarget).run();

		System.out.println("Running Detection ... for +" + trainingSizeTemp
				+ " for " + trainingTarget + "_" + startID + "_" + endId
				+ "  reports ");

		// Get the training size of this chunk

		/*
		 * trainingSizeTemp = trainingSizeMap.get(trainingTarget + "_" +
		 * currentMonth + "_" + currentYear);
		 */
		String type = "";
		if (StartDrifting.BM25Fext) {
			type = "/with-query-no-categorial.cfg ";
		} else {

			type = "/full-textual-full-categorial.cfg ";


		}

		String command = StartDrifting.saveDirectory + "/dbrd.v2 -k "
				+ (StartDrifting.topN) + " --training-duplicates "
				+ trainingSizeTemp + " -i 1 -n  "
				+ trainingTarget + "Titles --recommend  "
				+ StartDrifting.ResultsDic + "/" + trainingTarget + "_"
				+ startID + "_" + endId + "_" + trainingSizeTemp + "_"
				+ startID + "_" + endId + "_" + "Results -r "
				+ StartDrifting.saveDirectory + type
				+ StartDrifting.saveDirectory + "/id-" + trainingTarget + "_"
				+ startID + "_" + endId + "_" + "-reports-large.txt";

		System.err.println("Running Command :" + command);
		executeCommand(command);

		System.gc();

		System.err.println("Simplging a file");

		parseResultsFile(new File(StartDrifting.ResultsDic + "/"
				+ trainingTarget + "_" + startID + "_" + endId + "_"
				+ trainingSizeTemp + "_" + startID + "_" + endId + "_"
				+ "Results"));

		System.err.println("Delete file ,,, " + StartDrifting.ResultsDic + "/"
				+ trainingTarget + "_" + startID + "_" + endId + "_"
				+ trainingSizeTemp + "_" + startID + "_" + endId + "_"
				+ "Results");
		// 原作者的：删除原始的Results文件，每个Result文件只保留剩下的topN个
		deleteFile(StartDrifting.ResultsDic + "/" + trainingTarget + "_"
				+ startID + "_" + endId + "_" + trainingSizeTemp + "_"
				+ startID + "_" + endId + "_" + "Results");

		// scnb加的：只保留reports-large.txt，留出足够的剩余空间
//		deleteFile(StartDrifting.saveDirectory + "/id-" + trainingTarget + "_"
//				+ startID + "_" + endId + "_" + "-reports-large.txt");

		deleteFile(StartDrifting.saveDirectory + "/id-" + trainingTarget + "_"
				+ startID + "_" + endId + "_" + "-reports.txt-mapping.txt");

		deleteFile(StartDrifting.saveDirectory + "/" + trainingTarget + "_"
				+ startID + "_" + endId + "_" + "-reports.txt");

		StartDrifting.progress++;
		System.err.println("Total Done is " + StartDrifting.progress
				+ " , Percentage: % " + ((double) StartDrifting.progress)
				/ ((double) StartDrifting.iteration));

	}

	public String executeCommand(String command) {

		StringBuffer output = new StringBuffer();

		Process p;
		try {
			p = Runtime.getRuntime().exec(command);
			p.waitFor();
			// BufferedReader dd=new BufferedReader(new
			// InputStreamReader(p.getInputStream()));
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					p.getInputStream()));

			// InputStreamReader streamReader= new
			// InputStreamReader(p.getInputStream());
			String line = "";
			while ((line = reader.readLine()) != null) {
				System.out.println(line + "\n");
			}

			System.err.println("Done with Command : " + command);

		} catch (Exception e) {
			e.printStackTrace();
		}

		return output.toString();

	}

	public void parseResultsFile(File filePath) {

		BufferedReader br = null;
		String line = "";
		String cvsSplitBy = " ";
		Boolean rangeIsCorrect = false;
		long overallCount = 0;
		String[] searchToGet = filePath.getName().split("_");
		double searchSpaceSize = Double.parseDouble(searchToGet[0]) + 2;

		boolean startOnlyDuplicates = true;

		File simpleFile = null;
		FileWriter writer = null;
		boolean notFoundYet = true;
		try {
			File file = filePath;
			String[] names = file.getName().split("_");

			File folder = new File(StartDrifting.ResultsDic + "Simple/");
			if (!folder.exists()) {
				if (folder.mkdir()) {
					System.out.println("Directory is created!");
				} else {
					System.out.println("Failed to create directory!");
				}
			}

			simpleFile = new File(StartDrifting.ResultsDic + "Simple/"
					+ filePath.getName());
			writer = new FileWriter(simpleFile, false);

			if (file.exists()) {
				// System.out.println("File is found successfully...");
			}
			br = new BufferedReader(new FileReader(file));

			short count = 0;

			boolean OneIteration = false;

			String orgLine = null;
			while ((line = br.readLine()) != null) {

				orgLine = line;
				line = line.trim().replaceAll(" +", " ");
				line = line.trim().replaceAll("= ", "=");

				// System.out.println("~ "+line);
				String[] values = line.split(cvsSplitBy);

				// System.out.println(line);
				if (values[0] == null || line.trim().length() == 0) {
					continue;
				}
				if (values[0].equals("Iteration")) {

					if (OneIteration) {
						break;
					}
					OneIteration = true;
					continue;
				}

				if (values[0].equals("Retrieving")) {

					if (values[2].equals("non-duplicate")) {
						notFoundYet = false;
					} else if (values[2].equals("duplicate")) {
						notFoundYet = true;
						startOnlyDuplicates = false;

					}

					if (startOnlyDuplicates) {
						notFoundYet = true;
					}

					if (notFoundYet) {
						writer.append(orgLine + "\n");
					}

					// System.out.println("Working on Bug Iteration " +
					// (++overallCount));
					count = 0;

				} else if (notFoundYet) {

					writer.append(orgLine + "\n");

					++count;

					if (StartDrifting.topN == count) {
						writer.append("\n");

						notFoundYet = false;
					}
				}

				writer.flush();
				// }

				// System.gc();
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

	public void deleteFile(String fileName) {

		File f = null;
		boolean bool = false;

		try {
			// create new file
			f = new File(fileName);

			// tries to delete a non-existing file
			bool = f.delete();

			// prints
			System.out.println("File deleted: " + bool);

			// creates file in the system
			f.createNewFile();

			// createNewFile() is invoked
			System.out.println("createNewFile() method is invoked");

			// tries to delete the newly created file
			bool = f.delete();

			// print
			System.out.println("File deleted: " + bool);

		} catch (Exception e) {
			// if any error occurs
			// e.printStackTrace();
		}
	}

}